<!DOCTYPE html>
<html>
  <head>
    <meta http-equiv="Content-type" content="text/html; charset=utf-8">
    <title>Breakout - A fast fun game</title>
    <script type="text/javascript" src="http://code.jquery.com/jquery-1.7.2.min.js" />
    <script type="text/javascript">
      /* Breakout JavaScript by Louis Watson */
      var brickColors = 0;
      var bricks = [
        [0,0,0,0,0,0,0,0,0,0],
        [0,0,1,1,1,1,1,1,0,0],
        [0,2,2,2,2,2,2,2,2,0],
        [1,3,2,2,2,2,2,2,3,1],
        [1,3,3,3,4,4,3,3,3,1],
        [1,3,3,4,4,4,4,3,3,1],
        [1,3,3,3,4,4,3,3,3,1],              
        [0,1,1,2,2,2,2,1,1,0],
        [0,0,1,1,1,1,1,1,0,0]
      ]; // Brick Layout: 1 is orange, 2 is green, 3 is gray, 0 means no brick
      var brickSize = [0, 12];
      var ballDelta = [0, 0];
      var ballLocation = [0, 0];
      var ballRadius = 6;
      var canvas; // this assigns the canvas element
      var context; // this gets the 2D context from the canvas
      var gameLoop;
      var paddleDelta = [0, 0];
      var paddleLocation = [0, 0];
      var paddleMove;
      var paddleSize = [100, 10];
      var paddleSpeed = 10;
      var score = 0;
      var scoreHeight = 30;

      function animate () {
        context.clearRect(0, 0, canvas.width, canvas.height);
        renderBricks();
        renderScore();
        moveBall();
        movePaddle();
        renderPaddle();
        renderBall();
      }

      function ballCollideX() {
        var bumpedX = false;	
        for (var i = 0; i < bricks.length; i++) {
          for (var j = 0; j < bricks[i].length; j++) {
            if (bricks[i][j] > 0) { // if brick is still visible
              var brick = [j * brickSize[0], i * brickSize[1]];
              if (((ballLocation[0] + ballDelta[0] + ballRadius >= brick[0]) &&
                   (ballLocation[0] + ballRadius <= brick[0])) // barely touching from left
                  || ((ballLocation[0] + ballDelta[0] - ballRadius <= brick[0] + brickSize[0]) &&
                      (ballLocation[0] - ballRadius >= brick[0] + brickSize[0])) // barely touching from right
                 ){		
                if ((ballLocation[1] + ballDelta[1] -ballRadius <= brick[1] + brickSize[1]) &&
                    (ballLocation[1] + ballDelta[1] + ballRadius >= brick[1])) {													
                  // weaken brick and increase score
                  explodeBrick(i,j);
                  bumpedX = true;
                }
              }
            }
          }
        }
        return bumpedX;
      }
      
      function ballCollideY() {
        var bumpedY = false;
        for (var i = 0; i < bricks.length; i++) {
          for (var j=0; j < bricks[i].length; j++) {
            if (bricks[i][j]){ // if brick is still visible
              var brick = [j * brickSize[0], i * brickSize[1]];
              if (
                // barely touching from below
                ((ballLocation[1] + ballDelta[1] - ballRadius <= brick[1] + brickSize[1]) &&
                 (ballLocation[1] - ballRadius >= brick[1] + brickSize[1]))
                ||
                // barely touching from above
                ((ballLocation[1] + ballDelta[1] + ballRadius >= brick[1]) &&
                 (ballLocation[1] + ballRadius <= brick[1] ))){
                if (ballLocation[0] + ballDelta[0] + ballRadius >= brick[0] &&
                    ballLocation[0] + ballDelta[0] - ballRadius<= brick[0] + brickSize[0]){										
                  // weaken brick and increase score
                  explodeBrick(i, j);							
                  bumpedY = true;
                }						
              }
            }
          }
        }
        return bumpedY;
      }

      function endGame(){
        clearInterval(gameLoop);
        context.fillText('The End!!!!', canvas.width / 2, canvas.height / 2);
      }
        
      function explodeBrick(i, j) {
        // First weaken the brick (0 means brick has gone)
        bricks[i][j] --;
        
        if (bricks[i][j]>0){
          // The brick is weakened but still around. Give a single point.
          score += 4;
        } else {
          // give player an extra point when the brick disappears
          score += 8;		
          // breakingSound.play();
        }
      }
      
      function initVars() {
        paddleLocation[0] = (canvas.width - paddleSize[0]) / 2;
        paddleLocation[1] = canvas.height - scoreHeight - paddleSize[1];
        ballLocation[0] = canvas.width / 2;
        ballLocation[1] = paddleLocation[1] - (ballRadius + 1);
        brickSize[0] = canvas.width / bricks[0].length;
      }

      function moveBall(){
        // First check if we will bump into something
        
        // If top of the ball touches the top then reverse Y direction
        if (ballLocation[1] + ballDelta[1] - ballRadius < 0 || ballCollideY()){
          ballDelta[1] = -ballDelta[1];
          // bouncingSound.play();
        }
        // If the bottom of the ball touches the bottom of the screen then end the game
        if (ballLocation[1] + ballDelta[1] + ballRadius > canvas.height){
          endGame();
        }
        // If side of ball touches either side of the wall then reverse X direction
        //left of ball moves too far left
        if ((ballLocation[0] + ballDelta[0] - ballRadius < 0) ||
            //or right side of ball moves too far right
            (ballLocation[0] + ballDelta[0] + ballRadius > canvas.width)
            // or if ball collides in Y direction with bricks
            || ballCollideX()
           ){  
          ballDelta[0] = -ballDelta[0];
          // bouncingSound.play();
        }
        // if bottom of ball reaches the top of paddle,
        if (ballLocation[1] + ballDelta[1] + ballRadius >= paddleLocation[1]){
          // and it is positioned between the two ends of the paddle (is on top)
          if (ballLocation[0] + ballDelta[0] >= paddleLocation[0] && ballLocation[0] + ballDelta[0] <= paddleLocation[0] + paddleSize[0]){
            ballDelta[1] = - ballDelta[1];
            // bouncingSound.play();
          }
        }
        // Move the ball
        ballLocation[0] += ballDelta[0];
        ballLocation[1] += ballDelta[1];
      }
        
      function movePaddle(){
        if (paddleMove == 'LEFT'){
          paddleDelta[0] = -paddleSpeed;
        } else if (paddleMove == 'RIGHT'){
          paddleDelta[0] = paddleSpeed;
        } else {
          paddleDelta[0] = 0;
        }
        // If paddle reaches the ends, then don't let it move
        if (paddleLocation[0] + paddleDelta[0] < 0 || paddleLocation[0] + paddleDelta[0] + paddleSize[0] > canvas.width){
          paddleDelta[0] = 0;
        }
        paddleLocation[0] += paddleDelta[0];
      }

      function randomRGB() {
        return 'rgb(' + Math.floor((Math.random() * 255) + 1) + ', ' + Math.floor((Math.random() * 255) + 1) + ', ' + Math.floor((Math.random() * 255) + 1) + ')';
      }
        
      function renderBall() {
        // Context.beginPath when you draw primitive shapes
        context.beginPath();
        context.arc(ballLocation[0], ballLocation[1], ballRadius, 0, Math.PI*2, true); // From 0 to 2xPI radians (full circle)
        context.fill(); // Fill up the path that you just drew	
      }

      function renderBrick(x, y, t) {
        if(t > 0) {
          context.fillStyle = renderBrickColors[x, y];
          context.fillRect(x * brickSize[0], y * brickSize[1], brickSize[0], brickSize[1]);
          // Also draw blackish border around the brick
          context.strokeRect(x * brickSize[0] + 1, y * brickSize[1] + 1, brickSize[0] - 2, brickSize[1] - 2);
        } else {
          context.clearRect(x * brickSize[0], y * brickSize[1], brickSize[0], brickSize[1]);
        }
      }
        
      function renderBrickColors() {
        if(brickColors == 0) {
          brickColors = bricks;
          for (var i = 0; i < bricks.length; i++) {
            for (var j = 0; j < bricks[i].length; j++) {
              brickColors[i, j] = randomRGB();
            }
          }
        }
        return brickColors;
      }

      function renderBricks() {
        for (var i = 0; i < bricks.length; i++) {
          for (var j = 0; j < bricks[i].length; j++) {
            renderBrick(j, i, bricks[i][j]);
          }
        }
      }
      
      function renderPaddle() {
        context.fillRect(paddleLocation[0], paddleLocation[1], paddleSize[0], paddleSize[1]);
      }
        
      function renderScore() {
        //Set the text font and color
        context.fillStyle = 'rgb(50,100,50)';
        context.font = "20px Times New Roman";
        //Clear the bottom 30 pixels of the canvas
        context.clearRect(0, canvas.height - scoreHeight, canvas.width, scoreHeight);	
        // Write Text 5 pixels from the bottom of the canvas
        context.fillText('Score: ' + score, 10, canvas.height - 5);
      }
        
      function startGame(){
        ballDelta[1] = -4;
        ballDelta[0] = -2;
        paddleMove = 'NONE';
        paddleDelta[0] = 0;
        brickColors = 0;
        initVars();
        // call the animate() function every 200ms until clearInterval(gameLoop) is called
        gameLoop = setInterval(animate,20);
      }

      $(function() {
        canvas = $('#canvas');
        context = canvas.getContext("2d");
        // Start Tracking Keystokes
        $(document).keydown(function(e) {
          switch(e.which) {
            case $.ui.keyCode.LEFT:
              paddleMove = 'LEFT';
              break;
              
            case $.ui.keyCode.UP:
              startGame();
              break;
              
            case $.ui.keyCode.RIGHT:
              paddleMove = 'RIGHT';
              break;
              
            default: return; // allow other keys to be handled
          };
          // prevent default action (eg. page moving up/down)
          // but consider accessibility (eg. user may want to use keys to choose a radio button)
          e.preventDefault();
        });
          
        $(document).keyup(function(e) {
          switch(e.which) {
            case $.ui.keyCode.LEFT:
              paddleMove = 'NONE';
              break;
            case $.ui.keyCode.RIGHT:
              paddleMove = 'NONE';
              break;
            default: return; // allow other keys to be handled
          }
          // prevent default action (eg. page moving up/down)
          // but consider accessibility (eg. user may want to use keys to choose a radio button)
          e.preventDefault();
        });
      });
    </script>
  </head>
  <body>  
    <canvas id="canvas">Spunky!</canvas>
  </body>
</html>
